package factura.dao;

import java.io.Serializable;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class HibernateUtilDAO {
	private static final SessionFactory sessionFactory = construirSessionFactory();
	private static Session sesion = getSession();

	private static SessionFactory construirSessionFactory() {
		try {
			// Crea un nuevo SessionFactory a partir de hibernate.cfg.xml
			return new Configuration().configure(
					"factura/xml/hibernate.cfg.xml").buildSessionFactory();
		} catch (Throwable ex) {
			// Si existe error al inicializar
			System.out.println("Error creando SessionFactory: " + ex);
			ex.printStackTrace();
			throw new ExceptionInInitializerError(ex);
		}
	}

	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public static Session getSession() {
		if (sesion == null)
			sesion = getSessionFactory().openSession();
		return sesion;
	}

	/**
	 * finder generico que devuelve una lista de todos los objetos existentes en
	 * una tabla.
	 * 
	 * @param entidadFuente
	 *            nombre de la entidad fuente.
	 * @param expresionOrderBy
	 *            expresion para ordenar (no debe incluir "order by"). Puede ser
	 *            null si no se desea ordenar el listado obtenido.
	 * @return Listado de objetos encontrados en la bdd.
	 * @throws Exception
	 *             Error de la capa DAO.
	 */
	public static List findAll(String entidadFuente, String expresionOrderBy)
			throws Exception {
		try {
			Session sesion;
			sesion = HibernateUtilDAO.getSessionFactory().openSession();
			sesion.beginTransaction();
			Query q;
			if (expresionOrderBy == null || expresionOrderBy.length() == 0)
				q = sesion.createQuery("From " + entidadFuente);
			else
				q = sesion.createQuery("From " + entidadFuente + " order by "
						+ expresionOrderBy);
			@SuppressWarnings("unchecked")
			List listado = q.list();
			sesion.getTransaction().commit();
			sesion.close();
			return listado;
		} catch (HibernateException e) {
			e.printStackTrace();
			throw new Exception("Ha ocurrido un error (DAO). " + e.getMessage());
		}
	}

	/**
	 * finder generico que devuelve una lista de todos los objetos existentes en
	 * una tabla.
	 * 
	 * @param entidadFuente
	 *            nombre de la entidad fuente.
	 * @return Listado de objetos encontrados en la bdd.
	 * @throws Exception
	 *             Error de la capa DAO.
	 */
	public static List findAll(String entidadFuente) throws Exception {
		return findAll(entidadFuente, null);
	}

	/**
	 * finder generico que devuelve una lista de los objetos existentes en una
	 * tabla que cumplen con la condicion especificada.
	 * 
	 * @param entidadFuente
	 *            nombre de la entidad fuente.
	 * @param expresionWhere
	 *            expresion que contiene la condicion a utilizar (no debe
	 *            incluir "where").
	 * @param expresionOrderBy
	 *            expresion para ordenar (no debe incluir "order by"). Puede ser
	 *            null si no se desea ordenar el listado obtenido.
	 * @return Listado de objetos encontrados en la bdd.
	 * @throws Exception
	 *             Error de la capa DAO.
	 */
	public static List findByFiltro(String entidadFuente,
			String expresionWhere, String expresionOrderBy) throws Exception {
		try {
			Session sesion;
			sesion = HibernateUtilDAO.getSessionFactory().openSession();
			sesion.beginTransaction();
			Query q;
			if (expresionOrderBy == null || expresionOrderBy.length() == 0)
				q = sesion.createQuery("From " + entidadFuente + " where "
						+ expresionWhere);
			else
				q = sesion.createQuery("From " + entidadFuente + " where "
						+ expresionWhere + " order by " + expresionOrderBy);
			@SuppressWarnings("unchecked")
			List listado = q.list();
			sesion.getTransaction().commit();
			sesion.close();
			return listado;
		} catch (HibernateException e) {
			e.printStackTrace();
			throw new Exception("Ha ocurrido un error (DAO). " + e.getMessage());

		}
	}

	public static List findByFiltro(String entidadFuente, String expresionWhere)
			throws Exception {
		return findByFiltro(entidadFuente, expresionWhere, null);
	}

	/**
	 * Busca la informacion de un objeto especifico.
	 * 
	 * @param clase
	 *            Class correspondiente al objeto buscado.
	 * @param clavePrimaria
	 *            objeto que representa al parametro de busqueda.
	 * @return datos del objeto, null si no encuentra.
	 * @throws Exception
	 *             Error de capa de persistencia (DAO).
	 */
	public static Object findByClavePrimaria(Class clase,
			Serializable clavePrimaria) throws Exception {
		if (clavePrimaria == null)
			throw new Exception(
					"Error: debe especificar el parametro para hacer la busqueda.");
		try {
			Session sesion;
			sesion = HibernateUtilDAO.getSessionFactory().openSession();
			sesion.beginTransaction();
			Object o;
			o = sesion.get(clase, clavePrimaria);
			sesion.getTransaction().commit();
			sesion.close();
			return o;
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("Ha ocurrido un error (DAO). " + e.getMessage());
		}
	}

	/**
	 * Inserta un nuevo objeto en la base de datos.
	 * 
	 * @param nuevoObjeto
	 *            datos del nuevo objeto.
	 * @throws Exception
	 *             Error de capa de persistencia (DAO).
	 */
	public static void insertarObjeto(Object nuevoObjeto) throws Exception {
		try {
			Session sesion;
			sesion = HibernateUtilDAO.getSessionFactory().openSession();
			sesion.beginTransaction();
			sesion.save(nuevoObjeto);
			sesion.getTransaction().commit();
			sesion.close();
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("Ha ocurrido un error (DAO): " + e.getMessage());
		}
	}

	/**
	 * Elimina la informacion de un objeto.
	 * 
	 * @param objeto
	 *            objeto a eliminar.
	 * @throws Exception
	 *             Error de capa de persistencia (DAO).
	 */
	public static void eliminarObjeto(Object objeto) throws Exception {
		try {
			Session sesion;
			sesion = HibernateUtilDAO.getSessionFactory().openSession();
			sesion.beginTransaction();
			sesion.delete(objeto);
			sesion.getTransaction().commit();
			sesion.close();
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("Ha ocurrido un error (DAO):" + e.getMessage());
		}
	}

	/**
	 * Elimina la informacion de un objeto.
	 * 
	 * @param clase
	 *            Class correspondiente al objeto a eliminar.
	 * @param clavePrimaria
	 *            parametro de busqueda.
	 * @throws Exception
	 *             Error de capa de persistencia (DAO).
	 */
	public static void eliminarObjeto(Class clase, Serializable clavePrimaria)
			throws Exception {
		Session sesion;
		Transaction tx;
		sesion = HibernateUtilDAO.getSessionFactory().openSession();
		tx = sesion.beginTransaction();
		try {
			Object o;
			o = sesion.get(clase, clavePrimaria);
			sesion.delete(o);
			tx.commit();
			sesion.close();
		} catch (Exception e) {
			tx.rollback();
			e.printStackTrace();
			throw new Exception("Ha ocurrido un error (DAO): " + e.getMessage());
		}
	}

	/**
	 * Actualiza la informacion de un objeto.
	 * 
	 * @param objeto
	 *            Datos del objeto para actualizar.
	 * @throws Exception
	 *             Error de capa de persistencia (DAO).
	 */
	public static void actualizar(Object objeto) throws Exception {
		try {
			Session sesion;
			sesion = HibernateUtilDAO.getSessionFactory().openSession();
			sesion.beginTransaction();
			sesion.update(objeto);
			sesion.getTransaction().commit();
			sesion.close();
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("Ha ocurrido un error (DAO): " + e.getMessage());
		}
	}
}
